{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 9. GIL(Global Interpreter Lock) 全局解释器锁"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 9.1 GIL 基础\n",
    "\n",
    "- 一是设计者为了规避类似于内存管理这样的复杂的竞争风险问题（race condition）；\n",
    "- 二是因为 CPython 大量使用 C 语言库，但大部分 C 语言库都不是原生线程安全的（线程安全会降低性能和增加复杂度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "def CountDown(n):\n",
    "  while n > 0:\n",
    "    n -= 1;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: total: 2.52 s\n",
      "Wall time: 2.51 s\n"
     ]
    }
   ],
   "source": [
    "%time CountDown(100000000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Time taken: 2.5804234000006545 seconds\n"
     ]
    }
   ],
   "source": [
    "from threading import Thread\n",
    "import time\n",
    "\n",
    "n = 100000000\n",
    "\n",
    "t1 = Thread(target=CountDown,args=(n//2,))\n",
    "t2 = Thread(target=CountDown,args=(n//2,))\n",
    "\n",
    "start_time = time.perf_counter()\n",
    "t1.start()\n",
    "t2.start()\n",
    "t1.join()\n",
    "t2.join()\n",
    "end_time = time.perf_counter()\n",
    "print(f\"Time taken: {end_time - start_time} seconds\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import sys\n",
    "a = []\n",
    "b = a\n",
    "sys.getrefcount(a)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import psutil\n",
    "\n",
    "# 显示当前 python 程序占用的内存大小\n",
    "def show_memory_info(hint):\n",
    "    pid = os.getpid()\n",
    "    p = psutil.Process(pid)\n",
    "    \n",
    "    info = p.memory_full_info()\n",
    "    memory = info.uss / 1024. / 1024\n",
    "    print('{} memory used: {} MB'.format(hint, memory))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "initial memory used: 10.23828125 MB\n",
      "after a created memory used: 394.97265625 MB\n",
      "finished memory used: 13.64453125 MB\n"
     ]
    }
   ],
   "source": [
    "def func():\n",
    "    show_memory_info('initial')\n",
    "    a = [i for i in range(10000000)]\n",
    "    show_memory_info('after a created')\n",
    "\n",
    "func()\n",
    "show_memory_info('finished')\n",
    "\n",
    "########## 输出 ##########\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "initial memory used: 420.0546875 MB\n",
      "after a created memory used: 419.078125 MB\n",
      "finished memory used: 418.77734375 MB\n"
     ]
    }
   ],
   "source": [
    "def func():\n",
    "    show_memory_info('initial')\n",
    "    global a\n",
    "    a = [i for i in range(10000000)]\n",
    "    show_memory_info('after a created')\n",
    "\n",
    "func()\n",
    "show_memory_info('finished')\n",
    "\n",
    "########## 输出 ##########\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "initial memory used: 417.79296875 MB\n",
      "after a created memory used: 800.1171875 MB\n",
      "finished memory used: 421.765625 MB\n"
     ]
    }
   ],
   "source": [
    "def func():\n",
    "    show_memory_info('initial')\n",
    "    a = [i for i in range(10000000)]\n",
    "    show_memory_info('after a created')\n",
    "    return a\n",
    "\n",
    "a = func()\n",
    "show_memory_info('finished')\n",
    "\n",
    "########## 输出 ##########\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "3\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "\n",
    "a = []\n",
    "\n",
    "# 两次引用，一次来自 a，一次来自 getrefcount\n",
    "print(sys.getrefcount(a))\n",
    "\n",
    "def func(a):\n",
    "    # 四次引用，a，python 的函数调用栈，函数参数，和 getrefcount\n",
    "    print(sys.getrefcount(a))\n",
    "\n",
    "func(a)\n",
    "\n",
    "# 两次引用，一次来自 a，一次来自 getrefcount，函数 func 调用已经不存在\n",
    "print(sys.getrefcount(a))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "3\n",
      "8\n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "\n",
    "a = []\n",
    "\n",
    "print(sys.getrefcount(a)) # 两次\n",
    "\n",
    "b = a\n",
    "\n",
    "print(sys.getrefcount(a)) # 三次\n",
    "\n",
    "c = b\n",
    "d = b\n",
    "e = c\n",
    "f = e\n",
    "g = d\n",
    "\n",
    "print(sys.getrefcount(a)) # 八次\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "initial memory used: 36.4375 MB\n",
      "after a created memory used: 416.44921875 MB\n",
      "finish memory used: 58.1796875 MB\n"
     ]
    },
    {
     "ename": "NameError",
     "evalue": "name 'a' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mNameError\u001b[39m                                 Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[19]\u001b[39m\u001b[32m, line 13\u001b[39m\n\u001b[32m     10\u001b[39m gc.collect()\n\u001b[32m     12\u001b[39m show_memory_info(\u001b[33m'\u001b[39m\u001b[33mfinish\u001b[39m\u001b[33m'\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m13\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[43ma\u001b[49m)\n\u001b[32m     15\u001b[39m \u001b[38;5;66;03m########## 输出 ##########\u001b[39;00m\n",
      "\u001b[31mNameError\u001b[39m: name 'a' is not defined"
     ]
    }
   ],
   "source": [
    "import gc\n",
    "\n",
    "show_memory_info('initial')\n",
    "\n",
    "a = [i for i in range(10000000)]\n",
    "\n",
    "show_memory_info('after a created')\n",
    "\n",
    "del a\n",
    "gc.collect()\n",
    "\n",
    "show_memory_info('finish')\n",
    "print(a)\n",
    "\n",
    "########## 输出 ##########\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "initial memory used: 56.94921875 MB\n",
      "after a, b created memory used: 820.6796875 MB\n",
      "finished memory used: 57.98046875 MB\n"
     ]
    }
   ],
   "source": [
    "import gc\n",
    "def func():\n",
    "    show_memory_info('initial')\n",
    "    a = [i for i in range(10000000)]\n",
    "    b = [i for i in range(10000000)]\n",
    "    show_memory_info('after a, b created')\n",
    "    a.append(b)\n",
    "    b.append(a)\n",
    "\n",
    "func()\n",
    "gc.collect()\n",
    "show_memory_info('finished')\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Collecting objgraph\n",
      "  Downloading objgraph-3.6.2-py3-none-any.whl.metadata (12 kB)\n",
      "Downloading objgraph-3.6.2-py3-none-any.whl (17 kB)\n",
      "Installing collected packages: objgraph\n",
      "Successfully installed objgraph-3.6.2\n"
     ]
    }
   ],
   "source": [
    "! pip install objgraph"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Graph written to D:\\MyConfiguration\\yyf\\AppData\\Local\\Temp\\objgraph-vomo6fvw.dot (8 nodes)\n",
      "Graph viewer (xdot) and image renderer (dot) not found, not doing anything else\n"
     ]
    }
   ],
   "source": [
    "import objgraph\n",
    "\n",
    "a = [1, 2, 3]\n",
    "b = [4, 5, 6]\n",
    "\n",
    "a.append(b)\n",
    "b.append(a)\n",
    "\n",
    "objgraph.show_refs([a])"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
